﻿using System.Windows;
using System.Windows.Input;

namespace XEvolve.Presentation.Input
{
    public class CommandSource
    {
        public static DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command",
                                                                                           typeof(ICommand),
                                                                                           typeof(CommandSource), new FrameworkPropertyMetadata(OnCommandChanged));

        public static void SetCommand(DependencyObject o, ICommand value)
        {
            o.SetValue(CommandProperty, value);
        }

        public static ICommand GetCommand(DependencyObject o)
        {
            return (ICommand) o.GetValue(CommandProperty);
        }

        public static DependencyProperty ParameterProperty = DependencyProperty.RegisterAttached("Parameter",
                                                                                   typeof(object),
                                                                                   typeof(CommandSource));

        public static void SetParameter(DependencyObject o, object value)
        {
            o.SetValue(ParameterProperty, value);
        }

        public static object GetParameter(DependencyObject o)
        {
            return o.GetValue(ParameterProperty);
        }

        public static DependencyProperty TargetProperty = DependencyProperty.RegisterAttached("Target",
                                                                                           typeof(IInputElement),
                                                                                           typeof(CommandSource));

        public static void SetTarget(DependencyObject o, IInputElement value)
        {
            o.SetValue(TargetProperty, value);
        }

        public static IInputElement GetTarget(DependencyObject o)
        {
            return (IInputElement) o.GetValue(TargetProperty);
        }

        public static DependencyProperty TriggerEventProperty = DependencyProperty.RegisterAttached("TriggerEvent",
                                                                                           typeof(RoutedEvent), typeof(CommandSource), new FrameworkPropertyMetadata(UIElement.MouseLeftButtonUpEvent, OnTriggerEventChanged));

        public static void SetTriggerEvent(DependencyObject o, object value)
        {
            o.SetValue(TriggerEventProperty, value);
        }

        public static RoutedEvent GetTriggerEvent(DependencyObject o)
        {
            return (RoutedEvent)o.GetValue(TriggerEventProperty);
        }


        private static void OnTriggerEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = (UIElement)d;
            if (e.OldValue != null)
            {
                element.RemoveHandler((RoutedEvent) e.OldValue, new RoutedEventHandler(ExecuteCommand));
            }
            if (e.NewValue != null && GetCommand(element) != null)
            {
                element.AddHandler((RoutedEvent) e.NewValue, new RoutedEventHandler(ExecuteCommand));
            }
        }

        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var triggerEvent = GetTriggerEvent(d);
            SetTriggerEvent(d, null);
            SetTriggerEvent(d, triggerEvent);
        }

        private static void ExecuteCommand(object sender, RoutedEventArgs e)
        {
            var element = (UIElement)sender;
            var command = GetCommand(element);
            var parameter = GetParameter(element);
            var target = GetTarget(element);

            var commandTarget = target ?? element;

            if (command is RoutedCommand)
            {
                ((RoutedCommand)command).Execute(parameter, commandTarget);
            } else
            {
                command.Execute(parameter);
            }            
        }
    }
}
